Current Weather Quicklooks#
Code to Create Plots#
Show code cell source
import sage_data_client
from bokeh.models.formatters import DatetimeTickFormatter
import hvplot.pandas
import hvplot.xarray
import holoviews as hv
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import xarray as xr
import matplotlib.pyplot as plt
from metpy.plots import USCOUNTIES
import metpy.calc as mpcalc
import act
import numpy as np
import pandas as pd
import warnings
from bokeh.models import DatetimeTickFormatter
import panel as pn
start = "-6h"
def apply_formatter(plot, element):
plot.handles['xaxis'].formatter = DatetimeTickFormatter(hours='%m/%d/%Y \n %H:%M',
minutes='%m/%d/%Y \n %H:%M',
hourmin='%m/%d/%Y \n %H:%M',
days='%m/%d/%Y \n %H:%M',
months='%m/%d/%Y \n %H:%M')
xr.set_options(keep_attrs=True)
warnings.filterwarnings("ignore")
hv.extension("bokeh")
# Dictionary for renaming to standard names
variable_rename_dict = {'wxt.env.humidity':'relative_humidity',
'wxt.env.pressure':'air_pressure',
'wxt.env.temp':'air_temperature',
'wxt.heater.temp':'heater_temperature',
'wxt.heater.volt':'heater_voltage',
'wxt.rain.accumulation':'rain_accumulation',
'wxt.wind.direction':'wind_direction',
'wxt.wind.speed':'wind_speed',
'sys.gps.lat':'latitude',
'sys.gps.lon':'longitude',
}
# Dictionary for units that are missing
units_dict = {'wxt.env.temp': 'degC',
'wxt.env.pressure':'hPa',
'wxt.env.humidity':'percent',
'wxt.wind.speed':'m/s',
'wxt.wind.direction':'degrees'}
def generate_data_array(df, variable, rename_variable_dict=variable_rename_dict):
new_variable_name = rename_variable_dict[variable]
df_variable= df.loc[df.name == variable]
ds = df_variable.to_xarray().rename({'value':new_variable_name,
'timestamp':'time',
'meta.vsn':'node'})
ds[new_variable_name].attrs['units'] = df_variable['meta.units'].values[0]
ds['time'] = pd.to_datetime(ds.time)
ds.attrs['datastream'] = ds.node.values[0]
return ds[[new_variable_name]]
def generate_dataset(df, variables, rename_variable_dict=variable_rename_dict):
try:
reindexed = df.set_index(['meta.vsn', 'timestamp'])
except:
reindexed = df.set_index(['timestamp'])
return xr.merge([generate_data_array(reindexed, variable) for variable in variables])
# Query and load for n numbder of days
wxt_df = sage_data_client.query(
start=start,
filter={
"sensor": "vaisala-wxt536",
"name": "wxt.env.*"
}
)
wxt_df1 = sage_data_client.query(
start=start,
filter={
"sensor": "vaisala-wxt536",
"name": "wxt.wind.*"
}
)
wxt_df = pd.concat([wxt_df, wxt_df1])
try:
# Discover what variables we have and what to load into xarray
wxt_variables = wxt_df.name.unique()
wxt_df['meta.units'] = wxt_df.name.map(units_dict)
wxt_ds = generate_dataset(wxt_df, wxt_variables).squeeze().metpy.parse_cf()
wxt_ds['air_dewpoint_temperature'] = mpcalc.dewpoint_from_relative_humidity(wxt_ds.air_temperature, wxt_ds.relative_humidity)
# Resample to 1 minute freqency
minute_ds = wxt_ds.resample(time='1T').mean()
plots = []
temp_plot = wxt_ds.air_temperature.hvplot(color='red',
label='Air Temperature (degC)')
dewp_plot = wxt_ds.air_dewpoint_temperature.hvplot(color='green',
label='Dewpoint Temperature (degC)')
plots.append((temp_plot * dewp_plot).opts(hooks=[apply_formatter]))
meteogram_variables = ['wind_speed', 'wind_direction']
for variable in meteogram_variables:
plots.append((wxt_ds[variable].hvplot.line(label='10 Hz Data') *
minute_ds[variable].hvplot.line(label='1 Minute Data')).opts(hooks=[apply_formatter]))
except:
plots = pn.Row(title='No Data Available')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[1], line 103
102 plots = []
--> 103 temp_plot = wxt_ds.air_temperature.hvplot(color='red',
104 label='Air Temperature (degC)')
105 dewp_plot = wxt_ds.air_dewpoint_temperature.hvplot(color='green',
106 label='Dewpoint Temperature (degC)')
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/hvplot/plotting/core.py:95, in hvPlotBase.__call__(self, x, y, kind, **kwds)
93 return pn.panel(plot, **panel_dict)
---> 95 return self._get_converter(x, y, kind, **kwds)(kind, x, y)
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/hvplot/converter.py:1275, in HoloViewsConverter.__call__(self, kind, x, y)
1273 dataset = dataset.redim(**self._redim)
-> 1275 obj = method(x, y)
1276 obj._dataset = dataset
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/hvplot/converter.py:2184, in HoloViewsConverter.image(self, x, y, z, data)
2183 if self.geo: params['crs'] = self.crs
-> 2184 return (element(data, [x, y], z, **params).redim(**redim)
2185 .apply(self._set_backends_opts, cur_opts=cur_opts, compat_opts=compat_opts))
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/holoviews/element/raster.py:291, in Image.__init__(self, data, kdims, vdims, bounds, extents, xdensity, ydensity, rtol, **params)
290 yvals = self.dimension_values(1, False)
--> 291 b, t, ydensity, _ = util.bound_range(yvals, ydensity, self._time_unit)
292 bounds = BoundingBox(points=((l, b), (r, t)))
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/holoviews/core/util.py:2084, in bound_range(vals, density, time_unit)
2083 warnings.filterwarnings('ignore', r'invalid value encountered in (double_scalars|scalar divide)')
-> 2084 full_precision_density = compute_density(low, high, len(vals)-1)
2085 with np.errstate(over='ignore'):
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/holoviews/core/util.py:2115, in compute_density(start, end, length, time_unit)
2114 if isinstance(end, int): end = float(end)
-> 2115 diff = end-start
2116 if isinstance(diff, timedelta_types):
TypeError: unsupported operand type(s) for -: 'str' and 'str'
During handling of the above exception, another exception occurred:
TypeError Traceback (most recent call last)
Cell In[1], line 116
111 plots.append((wxt_ds[variable].hvplot.line(label='10 Hz Data') *
112 minute_ds[variable].hvplot.line(label='1 Minute Data')).opts(hooks=[apply_formatter]))
115 except:
--> 116 plots = pn.Row(title='No Data Available')
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/panel/layout/base.py:808, in ListPanel.__init__(self, *objects, **params)
806 if not resolve_ref(objects) or iscoroutinefunction(objects):
807 params['objects'] = [panel(pane) for pane in objects]
--> 808 super(Panel, self).__init__(**params)
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/panel/reactive.py:556, in Reactive.__init__(self, refs, **params)
554 if refs:
555 param.bind(self._sync_refs, *refs, watch=True)
--> 556 super().__init__(**params)
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/panel/reactive.py:118, in Syncable.__init__(self, **params)
116 def __init__(self, **params):
117 self._themer = None
--> 118 super().__init__(**params)
120 # Useful when updating model properties which trigger potentially
121 # recursive events
122 self._updating = False
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/panel/viewable.py:694, in Viewable.__init__(self, **params)
692 def __init__(self, **params):
693 hooks = params.pop('hooks', [])
--> 694 super().__init__(**params)
695 self._hooks = hooks
697 self._update_loading()
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/panel/viewable.py:532, in Renderable.__init__(self, **params)
530 self._comms = {}
531 self._kernels = {}
--> 532 super().__init__(**params)
533 self._found_links = set()
534 self._logger = logging.getLogger(f'{__name__}.{type(self).__name__}')
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/panel/viewable.py:298, in Layoutable.__init__(self, **params)
296 if 'design' not in params and self.param.design.default is None:
297 params['design'] = config.design
--> 298 super().__init__(**params)
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/param/parameterized.py:4148, in Parameterized.__init__(self, **params)
4146 if self.param.name.default == self.__class__.__name__:
4147 self.param._generate_name()
-> 4148 refs, deps = self.param._setup_params(**params)
4149 object_count += 1
4151 self._param__private.initialized = True
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/param/parameterized.py:1678, in as_uninitialized.<locals>.override_initialization(self_, *args, **kw)
1676 original_initialized = parameterized_instance._param__private.initialized
1677 parameterized_instance._param__private.initialized = False
-> 1678 ret = fn(self_, *args, **kw)
1679 parameterized_instance._param__private.initialized = original_initialized
1680 return ret
File /usr/share/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/param/parameterized.py:1934, in Parameters._setup_params(self_, **params)
1932 desc = self_.cls.get_param_descriptor(name)[0] # pylint: disable-msg=E1101
1933 if not desc:
-> 1934 raise TypeError(
1935 f"{self.__class__.__name__}.__init__() got an unexpected "
1936 f"keyword argument {name!r}"
1937 )
1939 pobj = objects.get(name)
1940 if pobj is None or not pobj.allow_refs:
1941 # Until Parameter.allow_refs=True by default we have to
1942 # speculatively evaluate a values to check whether they
1943 # contain a reference and warn the user that the
1944 # behavior may change in future.
TypeError: Row.__init__() got an unexpected keyword argument 'title'
Meteogram with Temperature, Dewpoint, and Winds#
This is what we call a meteogram, which is a timeseries of:
Temperature and Dewpoint (same plot)
Wind speed and direction (different plots)
The data is collected at 10 Hertz (10 observations per second) and averaged to 1 Hertz (1 per second) for the wind plots to illustrate turbulence!
Show code cell source
if len(plots) > 0:
display(hv.Layout(plots).cols(1))
else:
print('Issue with wxt datastream')